﻿using AppSocketModel;
using AppSocketService.Account;
using AppSocketService.Device;
using AppSocketService.Location;
using AppSocketService.ProductPerson;
using BCGPSCommon; 
using BCGPSMongoData;
using LJD.IMS.Utility;
using MongoDB.Driver;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Text;

namespace AppSocketService.Vehicle
{
    public class VehiclePersonService : ServiceBase, IVehiclePersonService
    {
        #region var
        // 账户车辆信息表前缀   
        private readonly MongoDBCommand<VehicleDto> mongoCommand = new MongoDBCommand<VehicleDto>("AccountVehicle");
        private readonly IRedisService redisService;
        private readonly AccountDto CurrentAccount;

        private readonly IAccountPersonService accountService;
        private readonly ILocationPersonService locationPersonService;
        private readonly IDeviceService deviceService;
        #endregion

        #region 构造函数
        public VehiclePersonService(IRedisService redisService)
        {
            this.redisService = redisService;
        }

        public VehiclePersonService(IClaimsAccessor claimsAccesso, IRedisService redisService, IAccountPersonService accountService, ILocationPersonService locationPersonService, IDeviceService deviceService) : base(claimsAccesso)
        {
            this.redisService = redisService;
            this.accountService = accountService;
            this.locationPersonService = locationPersonService;
            this.deviceService = deviceService;
            CurrentAccount = accountService.GetCurrentAccount();
            if (CurrentAccount == null)
                throw new Exception("登录账户异常,请重新登录 !!!");
        }
        #endregion
        
        #region  初始化REDIS 获取全部车辆列表
        public List<VehicleDto> InitRedisGetListAll()
        {
            return mongoCommand.SelectDocumentsAsync(s => s.CompanyId == 0).GetAwaiter().GetResult();
        }
        #endregion


        #region  添加新设备
        public VehicleDto AddNew(VehicleRequestDto vehicleRequestDto)
        {
            if (vehicleRequestDto.IMEI.Trim().Length < 13)
                throw new ArgumentException("请输入正确的IMEI号!");
            if (string.IsNullOrWhiteSpace(vehicleRequestDto.VehicleNo))
                throw new ArgumentException("请输入车牌号!");

            if (vehicleRequestDto.vehicleType == VehicleType.BUS || vehicleRequestDto.vehicleType == VehicleType.CAR || vehicleRequestDto.vehicleType == VehicleType.MINIBUS || vehicleRequestDto.vehicleType == VehicleType.VAN || vehicleRequestDto.vehicleType == VehicleType.HIGHRAILTRUCK || vehicleRequestDto.vehicleType == VehicleType.FLATTRUCK)
            {
                if (!StringHelper.IsVehicleNo(vehicleRequestDto.VehicleNo))
                    throw new ArgumentException("输入的车牌号不正确!");
            }

            var productPersonService = new ProductPersonService();
            if (!productPersonService.IsExist(vehicleRequestDto.IMEI))
                throw new ArgumentException($"IMEI[{vehicleRequestDto.IMEI}]设备不在产品库,请检查输入是否正确,或向产品提供商咨询!");


            var dtoImei = mongoCommand.SelectDocumentAsync(s => s.IMEI == vehicleRequestDto.IMEI).GetAwaiter().GetResult();
            if (dtoImei != null)
                throw new ArgumentException($"GPS设备IMEI号[{dtoImei.IMEI}]已经存在并被使用!");

            VehicleDto vehicleDto;
            if (CurrentAccount.CompanyId > 0)
            {
                vehicleDto = AddNewCompany(vehicleRequestDto);
            }
            else
            {
                vehicleDto = AddNewPerson(vehicleRequestDto);
            }

            LocationDto locationDto = new LocationDto();
            locationDto.IMEI = vehicleRequestDto.IMEI;
            locationDto.VehicleNo = vehicleRequestDto.VehicleNo;
            locationDto = locationPersonService.AddNew(locationDto);

            if (CurrentAccount.CompanyId > 0)
            {
                redisService.AddHashAsync(GeneralContainer.RedisNameSpaceAccountVehicle + CurrentAccount.CompanyId, vehicleDto.IMEI, vehicleDto).GetAwaiter().GetResult(); 
                redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEILocation + locationDto.IMEI, locationDto);
                return mongoCommand.SelectDocumentAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.IMEI == vehicleRequestDto.IMEI).GetAwaiter().GetResult();
            }
            else
            {
                redisService.AddHashAsync(GeneralContainer.RedisNameSpaceAccountVehiclePerson + CurrentAccount.AccountCode, vehicleDto.IMEI, vehicleDto).GetAwaiter().GetResult(); 
                redisService.AddAsync(GeneralContainer.RedisNameSpaceIMEILocation + locationDto.IMEI, locationDto);
                return mongoCommand.SelectDocumentAsync(s => s.CompanyId == 0 && s.AccountId == CurrentAccount.AccountId && s.IMEI == vehicleRequestDto.IMEI).GetAwaiter().GetResult();
            }

        }

        private VehicleDto AddNewCompany(VehicleRequestDto vehicleRequestDto)
        {
            var dto = mongoCommand.SelectDocumentAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.IMEI == vehicleRequestDto.IMEI).GetAwaiter().GetResult();
            if (dto != null)
                throw new ArgumentException("要添加设备IMEI已经存在!");

            VehicleDto vehicleDto = vehicleRequestDto.As<VehicleDto>();
            vehicleDto.AccountId = CurrentAccount.ParentAccountId;
            vehicleDto.CompanyId = CurrentAccount.CompanyId;
            vehicleDto.DriverPhone = CurrentAccount.Phone;

            vehicleDto.CreateTime = MongoDBDateTime.GetNowUtc();
            vehicleDto.ModifyTime = MongoDBDateTime.GetNowUtc();
            mongoCommand.InsertDocumentAsync(vehicleDto).GetAwaiter().GetResult();
            return vehicleDto;

        }
        private VehicleDto AddNewPerson(VehicleRequestDto vehicleRequestDto)
        { 
            var  dto = mongoCommand.SelectDocumentAsync(s => s.CompanyId == 0 && s.AccountId == CurrentAccount.AccountId && s.IMEI == vehicleRequestDto.IMEI).GetAwaiter().GetResult();
            if (dto != null)
                throw new ArgumentException("要添加设备IMEI已经存在!");


            VehicleDto vehicleDto = vehicleRequestDto.As<VehicleDto>();

            vehicleDto.CompanyId = CurrentAccount.CompanyId;
            vehicleDto.AccountId = CurrentAccount.AccountId;
            vehicleDto.DriverPhone = CurrentAccount.Phone;

            vehicleDto.CreateTime = MongoDBDateTime.GetNowUtc();
            vehicleDto.ModifyTime = MongoDBDateTime.GetNowUtc();
            mongoCommand.InsertDocumentAsync(vehicleDto).GetAwaiter().GetResult();
            return vehicleDto;
        }
        #endregion

        #region 修改车辆信息 根据 IMEI
        public VehicleDto Update(VehicleDto vehicleDto)
        {
            if (string.IsNullOrWhiteSpace(vehicleDto.VehicleNo))
                throw new ArgumentException("请输入车牌号!");

            if (vehicleDto.vehicleType == VehicleType.BUS || vehicleDto.vehicleType == VehicleType.CAR || vehicleDto.vehicleType == VehicleType.MINIBUS || vehicleDto.vehicleType == VehicleType.VAN || vehicleDto.vehicleType == VehicleType.HIGHRAILTRUCK || vehicleDto.vehicleType == VehicleType.FLATTRUCK)
            {
                if (!StringHelper.IsVehicleNo(vehicleDto.VehicleNo))
                    throw new ArgumentException("输入的车牌号不正确!");
            }


            if (CurrentAccount.CompanyId > 0)
                return UpdateCompany(vehicleDto);
            else
                return UpdatePerson(vehicleDto);
        }

        private VehicleDto UpdateCompany(VehicleDto vehicleDto)
        {
            if (vehicleDto.IMEI.Length < 13)
                throw new ArgumentException("请输入正确的IMEI !");
            if (!string.IsNullOrWhiteSpace(vehicleDto.DriverPhone))

                if (!StringHelper.IsMobilePhone(vehicleDto.DriverPhone))
                    throw new ArgumentException("输入的手机号不正确!");

            if (string.IsNullOrWhiteSpace(vehicleDto.IMEI))
                throw new ArgumentException("IMEI必须填写!");


            VehicleDto dto = mongoCommand.SelectDocumentAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.IMEI == vehicleDto.IMEI).GetAwaiter().GetResult();

            if (dto == null)
                throw new ArgumentException("找不到车辆信息!");



            vehicleDto.ModifyTime = DateTime.Now;
            var update = Builders<VehicleDto>.Update
                .Set(s => s.DriverPhone, vehicleDto.DriverPhone)
                .Set(s => s.DriverName, vehicleDto.DriverName)
                .Set(s => s.VehicleNo, vehicleDto.VehicleNo)
                .Set(s => s.VehicheTypeCode, vehicleDto.VehicheTypeCode)
                .Set(s => s.vehicleType, vehicleDto.vehicleType)
                .Set(s => s.ModifyTime, MongoDBDateTime.GetNowUtc());
            var ret = mongoCommand.UpdateDocumentAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.IMEI == vehicleDto.IMEI, update).GetAwaiter().GetResult();
            if (ret == null)
                throw new ArgumentException("修改失败,请重试!");

            LocationDto locationDto = locationPersonService.UpdateByImei(vehicleDto.VehicleNo, vehicleDto.IMEI);

            redisService.AddHashAsync(GeneralContainer.RedisNameSpaceAccountVehicle + CurrentAccount.CompanyId, vehicleDto.IMEI, vehicleDto).GetAwaiter().GetResult();


            return ret;

        }
        private VehicleDto UpdatePerson(VehicleDto vehicleDto)
        {
            if (vehicleDto.IMEI.Length < 13)
                throw new ArgumentException("请输入正确的IMEI !");
            if (!string.IsNullOrWhiteSpace(vehicleDto.DriverPhone))

                if (!StringHelper.IsMobilePhone(vehicleDto.DriverPhone))
                    throw new ArgumentException("输入的手机号不正确!");

            if (string.IsNullOrWhiteSpace(vehicleDto.IMEI))
                throw new ArgumentException("IMEI必须填写!");


            VehicleDto dto = mongoCommand.SelectDocumentAsync(s => s.CompanyId == 0 && s.AccountId == CurrentAccount.AccountId && s.IMEI == vehicleDto.IMEI).GetAwaiter().GetResult();

            if (dto == null)
                throw new ArgumentException("找不到车辆信息!");

            vehicleDto.ModifyTime = DateTime.Now;
            var update = Builders<VehicleDto>.Update
                .Set(s => s.DriverPhone, vehicleDto.DriverPhone)
                .Set(s => s.DriverName, vehicleDto.DriverName)
                .Set(s => s.VehicleNo, vehicleDto.VehicleNo)
                .Set(s => s.VehicheTypeCode, vehicleDto.VehicheTypeCode)
                .Set(s => s.vehicleType, vehicleDto.vehicleType)
                .Set(s => s.ModifyTime, DateTime.Now);
            var ret = mongoCommand.UpdateDocumentAsync(s => s.CompanyId == 0 && s.IMEI == vehicleDto.IMEI, update).GetAwaiter().GetResult();
            if (ret == null)
                throw new ArgumentException("修改失败,请重试!");

            LocationDto locationDto = locationPersonService.UpdateByImei(vehicleDto.VehicleNo, vehicleDto.IMEI);

            redisService.AddHashAsync(GeneralContainer.RedisNameSpaceAccountVehiclePerson + CurrentAccount.AccountCode, vehicleDto.IMEI, vehicleDto).GetAwaiter().GetResult();
            return ret;

        }
        #endregion

        #region 获取车辆信息通过IMEI 
        public VehicleDto GetVehicleByImei(string imei)
        {
            if (claimsAccessor.AccountRole == AccountRole.SYSTEM)
            {
                return mongoCommand.SelectDocumentAsync(s => s.IMEI == imei).GetAwaiter().GetResult();
            }
            if (CurrentAccount.CompanyId > 0)
            {
                var dto = redisService.GetHashObj<VehicleDto>(GeneralContainer.RedisNameSpaceAccountVehicle + CurrentAccount.CompanyId.ToString(), imei);
                if (dto != null)
                    return dto;
                else
                    return mongoCommand.SelectDocumentAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.AccountId == CurrentAccount.ParentAccountId && s.IMEI == imei).GetAwaiter().GetResult();
            }
            else
            {
                var dto = redisService.GetHashObj < VehicleDto>(GeneralContainer.RedisNameSpaceAccountVehiclePerson + CurrentAccount.AccountCode, imei);
                if (dto != null)
                    return dto;
                else
                    return mongoCommand.SelectDocumentAsync(s => s.CompanyId == 0 && s.AccountId == CurrentAccount.AccountId && s.IMEI == imei).GetAwaiter().GetResult();
            }
        }
        #endregion

        #region   通过车牌号获取车辆信息
        public List<VehicleDto> GetVehicleListByVehicleNo(string vehicleNo)
        {
            if (claimsAccessor.AccountRole == AccountRole.SYSTEM)
            {
                return mongoCommand.SelectDocumentsAsync(s => s.VehicleNo == vehicleNo).GetAwaiter().GetResult();
            }
            else
            {
                if (CurrentAccount.CompanyId > 0)
                { 
                        return mongoCommand.SelectDocumentsAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.VehicleNo == vehicleNo).GetAwaiter().GetResult();
                }
                else
                { 
                        return mongoCommand.SelectDocumentsAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.AccountId == CurrentAccount.AccountId && s.VehicleNo == vehicleNo).GetAwaiter().GetResult();
                }

            }
        }
        #endregion

        #region 获取当前账户车辆列表
        public List<VehicleDto> GetVehicleList()
        {
            if (CurrentAccount.CompanyId > 0)
            {
                return mongoCommand.SelectDocumentsAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.DriverPhone == CurrentAccount.AccountCode).GetAwaiter().GetResult();
            }
            else
            {
                var a = redisService.GetHashAllAsync(GeneralContainer.RedisNameSpaceAccountVehiclePerson + CurrentAccount.AccountCode).GetAwaiter().GetResult();
                if (a != null && a.Length > 0)
                {
                    List<VehicleDto> list = new List<VehicleDto>();
                    foreach (var item in a)
                    {
                        VehicleDto vehicleDto = JsonConvert.DeserializeObject<VehicleDto>(item.Value, GeneralContainer.JsonSerializerSettings);//不会产生异常
                        if (vehicleDto != null)
                            list.Add(vehicleDto);
                    }
                    return list;
                }
                else
                    return mongoCommand.SelectDocumentsAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.AccountId == CurrentAccount.AccountId).GetAwaiter().GetResult();
            }
        }
        #endregion

        #region 删除设备
        public void DeleteAll()
        {
            if (CurrentAccount.CompanyId > 0)
                throw new Exception("企业下的个人账户没有删除全部设备的权限!");
            var list = GetVehicleList();
            foreach (var item in list)
            {
                Delete(item.IMEI);
            }
        }

        public void Delete(string imei)
        { 
                if (CurrentAccount.CompanyId > 0)
                {
                    redisService.DeleteAsync(GeneralContainer.RedisNameSpaceIMEIAlarm + imei).GetAwaiter().GetResult();
                    redisService.DeleteHashObjAsync(GeneralContainer.RedisNameSpaceAccountVehicle + CurrentAccount.CompanyId, imei).GetAwaiter().GetResult();
                    mongoCommand.DeleteDocumentAsync(s => s.CompanyId == CurrentAccount.CompanyId && s.IMEI == imei).GetAwaiter().GetResult();
                    locationPersonService.Delete(imei);
                }
                else
                {
                    redisService.DeleteAsync(GeneralContainer.RedisNameSpaceIMEIAlarm + imei).GetAwaiter().GetResult();
                    redisService.DeleteHashObjAsync(GeneralContainer.RedisNameSpaceAccountVehiclePerson + CurrentAccount.AccountCode, imei).GetAwaiter().GetResult();
                    mongoCommand.DeleteDocumentAsync(s => s.CompanyId == 0 && s.AccountId == CurrentAccount.AccountId && s.IMEI == imei).GetAwaiter().GetResult();
                    locationPersonService.Delete(imei);
                } 
        }
        #endregion


        #region 获取指定车辆信息和定位信息
        public VehicleLocationDto GetVehicleLocation(string imei, GpsMapType gpsMapType)
        {
            VehicleLocationDto dto = GetVehicleByImei(imei).As<VehicleLocationDto>();
            if (dto != null)
            {
                dto.Location = locationPersonService.GetLocation(dto.IMEI, gpsMapType);
                dto.Device = deviceService.Get(dto.IMEI);
            }
            return dto;
        }
        #endregion


        #region 获取当前账户下全部车辆信息和定位信息 
        public List<VehicleLocationDto> GetVehicleLocationList(GpsMapType gpsMapType)
        {
            List<VehicleLocationDto> list = GetVehicleList().As<List<VehicleLocationDto>>();
            foreach (var item in list)
            {
                item.Location = locationPersonService.GetLocation(item.IMEI, gpsMapType);
                item.Device = deviceService.Get(item.IMEI);
            }
            return list;
        }
        #endregion

        #region  获取指定账户的车辆列表
        public PageableList<VehicleDto> SysGetVehicleList(string accountCode,  bool desc, int index, int size)
        {
            index = index > 0 ? index - 1 : 0;

            if (string.IsNullOrWhiteSpace(accountCode))
                throw new ArgumentException("请输入要查询的账号!");
            AccountDto account = accountService.GetAccountByCode(accountCode) ?? throw new ArgumentException("输入的账号不存在!");

            return mongoCommand.SelectDocumentsAsync(s => s.AccountId == account.AccountId,s=>s.CreateTime,desc,index*size,size).GetAwaiter().GetResult();
        }
        #endregion
    }
}
